#ifndef __CLIENT_CONNECTION_H__
#define __CLIENT_CONNECTION_H__ 1

#include <QObject>
#include <QWidget>
#include <QTcpSocket>
#include <QMutex>

#include "ui_constants.h"

/**
 * @brief this is the actual model for the stegit-2 control
 * @author rpoisel
 */

class CClientConnection : public QObject
{
	Q_OBJECT

public:

	enum EProtocolState
	{   
			PROTOCOL_NONE = 0,
			PROTOCOL_LENGTH,
			PROTOCOL_PAYLOAD,
	};  

	enum EClientState
	{
		CLIENT_DISCONNECTED = 0,
		CLIENT_CONNECTED,
		CLIENT_STARTED
	};

	CClientConnection(QString& pHost, quint16& pPort);
	virtual ~CClientConnection();

	/*---- start of send commands which are synced by sendCommand() ----*/
	bool requestStart();
	bool requestConfig();
	bool sendConfigSection(const QString& pSection);
	bool sendConfigKey(const QString& pSection, const QString& pKey, const QString& pValue);
	bool sendConfigStart();
	bool sendConfigEnd();
	/*---- end of send commands */

signals:
	void clientConnected(QString, quint16);
	void clientDisconnected();
	void connectionError(QString);
	void infoReceived(ELogLevel, QString);
	void configReceived(const QString& , const QString& , const QString& );
	void configReceivedEnd();
	void closeReceived();
	void extractBufferInfoReceived(quint32, quint32);
	void frameSendLengthReceived(quint32);
	void frameRecvLengthReceived(quint32, bool);
	void packetSendLengthReceived(quint32);
	void packetRecvLengthReceived(quint32, bool);
	void streamSendInfoReceived(int, int, quint32, bool);
	void streamSendDataReceived(void*, int);
	void streamRecvInfoReceived(int, int, quint32, bool);
	void streamRecvDataReceived(void*, int);
	void protocolWriteDataReceived(void*, int);
	void protocolReadFeedbackReceived(quint32, quint32);
	void embedAmpReceived(quint8);
	void extractAmpReceived(quint8);

private slots:
	void connected();
	void disconnected();
	void error(QAbstractSocket::SocketError pSocketError);
	void readyRead();
	bool sendDefenseValue(quint32 pValue);

	/*---- start of send commands (by slots) which are synced by sendCommand() ----*/
	void protocolReadDataSend(const void* pData, int pLength);
	/*---- end of send commands */

private:
	CClientConnection(const CClientConnection& );
	CClientConnection& operator=(const CClientConnection& );

	/**
	 * This methode will be called from readyRead() after a new received command.
	 * pData[0] includes the command. --> pLen always at least 1.
	 *
	 * @note pData buffer has the length pLen + 1. The extra byte is added by
	 *       readyRead() and '\0' terminated.
	 *
	 * @return False for received COMMAND_CLOSE_CONNECTION otherwise true.
	 */
	bool receivedCommand(char* pData, unsigned int pLen);

	/**
	 * @brief Create and send a command over the socket to the UI
	 *
	 * @note This methode use the mutex mCommandSendSync for sync!!!
	 * @note This methode create the 4 byte length field. The value of this
	 *       field is pLen (which already includes the command).
	 *
	 * @note A command need not use this methode to create the command header
	 *       and its payload but then it must use the mutex mCommandSendSync.
	 *
	 * @param pData Buffer which should be send. pData[0] must be the command
	 *        and after that the optional payload follow.
	 * @param pLen length of full command (command byte + the payload)
	 *        pLen must be >= 1.
	 * @return Value of pLen for successful transmission, otherwise a value
	 *         which is unequal pLen.
	 */
	qint64 sendCommand(quint8* pData, quint32 pLen);

	void printData(unsigned int pOffset, quint8* pData, unsigned int pLen);
	QString toHex(quint8 pValue);

	static const quint32 sMaxNetStringLen;

	QString mHost;
	quint16 mPort;
	EProtocolState mProtocolState;
	EClientState mClientState;
	quint32 mNumBytesToRead;
	QTcpSocket mTcpSocket;
	QMutex mSync;

	/**
	 * A UI command MUST use this mutex to guarantee the sending as one
	 * data block. Otherwise a command can be currupted (interlaced with a
	 * other command).
	 *
	 * The mutex must be locked before sending the first byte (this also
	 * includes the length-field for the command) and must be unlocked after
	 * sending the last byte.
	 *
	 * @note The methode sendCommand use this mutex. Therefore if the whole
	 *       command is send by sendCommand then the mutex is used and sync
	 *       is ok.
	 */
	QMutex mCommandSendSync;
};

#endif /* __CLIENT_CONNECTION_H__ */

